第27章 模拟算法
模拟算法(Simulation Algorithm)是一种通过模仿现实问题的运行过程或操作步骤来求解问题的算法。它照问题所描述的规则或流程,一步一步地进行计算和操作,最终得到问题的结果。
27.1 模拟算法核心概念
核心思路:按部就班复现题目流程,不需要复杂数学推导,完全按照题目给出的规则、步骤编写代码,实时记录状态变化。 适用场景:题目给出清晰、分步执行的过程(游戏、排队、物理运动、计时、流程操作等)。
27.2 模拟算法标准实现步骤
- 阅读理解完整流程,拆分每一步操作;
- 定义变量存储过程状态(时间、数量、位置、窗口空闲时间等);
- 使用循环/分支复现每一步规则;
- 每次操作后更新状态变量;
- 满足终止条件后输出最终结果。
27.3 模拟算法优缺点
优点
- 逻辑和题目描述一一对应,易懂、好写;
- 无需复杂数学公式,新手友好;
- 只要读懂流程就能实现,适用范围极广。
缺点
- 步骤极多时循环量大,运行效率偏低;
- 对文字细节敏感,漏一条规则就会结果错误;
- 大量状态记录会占用较多内存。
27.4 经典模拟代码示例
示例1:模拟掷骰子10次,统计点数和为7的次数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(0)); // 设置随机种子
int count7 = 0;
for(int i = 0; i < 10; i++)
{
int d1 = rand() % 6 + 1;
int d2 = rand() % 6 + 1;
int sum = d1 + d2;
printf("第%d次:%d+%d=%d\n", i+1, d1, d2, sum);
if(sum == 7) count7++;
}
printf("点数之和等于7的次数:%d\n", count7);
return 0;
}
示例2:银行多窗口排队模拟
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand(time(0));
int windows[3] = {0}; // 记录3个窗口的空闲时刻
int customer = 5;
for(int i = 0; i < customer; i++)
{
int service = rand() % 5 + 1; // 服务时长1~5
// 找到最早空闲窗口
int minT = windows[0], idx = 0;
for(int j = 1; j < 3; j++)
{
if(windows[j] < minT)
{
minT = windows[j];
idx = j;
}
}
int start = windows[idx];
int end = start + service;
windows[idx] = end;
cout << "客户" << i+1 << ":窗口" << idx+1
<< ",开始:" << start << ",结束:" << end << endl;
}
return 0;
}
示例3:时钟秒针走动模拟(输出10秒)
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
int main()
{
int h = 12, m = 30, s = 0;
for(int i = 0; i < 10; i++)
{
printf("%02d:%02d:%02d\n", h, m, s);
this_thread::sleep_for(chrono::seconds(1));
s++;
if(s == 60)
{
s = 0;
m++;
if(m == 60)
{
m = 0;
h++;
if(h == 24) h = 0;
}
}
}
return 0;
}
示例4:小球下落反弹模拟
题目:小球从10米落下,每次反弹高度为下落一半,模拟5次落地总路程、第5次反弹高度
#include <iostream>
using namespace std;
int main()
{
double h = 10.0;
double total = 0.0;
int times = 5;
for(int i = 0; i < times; i++)
{
total += h;
if(i < times - 1)
{
h /= 2;
total += h;
}
}
cout << "第5次落地总路程:" << total << "米" << endl;
cout << "第5次反弹高度:" << h / 2 << "米" << endl;
return 0;
}
27.5 模拟编写注意事项
- 逐字阅读题目规则,不漏任何限制条件;
- 状态变量初始化必须符合题目初始状态;
- 循环终止条件严格对应题目结束场景;
- 随机类模拟必须设置
srand(time(0))保证随机不重复; - 调试时打印中间状态,快速定位步骤逻辑错误。